/* 面向对象开发 */
/* 
注BUG：
    1.点击重新开始，雷数不会重新初始化
    2、当旗子下的数字为0时，旗子会覆盖掉且雷数也减少
    3、一开始就标记旗子时(不按左键，只按右键)，游戏也会自动通关
*/
// 生成实例
function Mine(tr, td, mineNum) {
    this.tr = tr; //行数
    this.td = td; //列数
    this.mineNum = mineNum; //雷的数量

    this.squares = []; //存储所有方块信息，二维数组[行，列]
    this.tds = []; //存储所有的单元格的DOM
    this.surplusMine = mineNum; //剩余雷的数量
    this.allRight = false; //小红旗标记是否全为雷,判断用户是否游戏成功

    this.parent = document.querySelector('.gameBox');
}

// 生成随机数组
Mine.prototype.randomNum = function () {
    var square = new Array(this.tr * this.td); //生成有长度(各自总数)的空数组
    for (var i = 0; i < square.length; i++) {
        square[i] = i;
    }
    square.sort(function () {
        return 0.5 - Math.random();
    });
    return square.slice(0, this.mineNum);
};

// 初始化
Mine.prototype.init = function () {
    // this.randomNum();
    var rn = this.randomNum(); //雷在格子里的位置
    var n = 0; //用来找到格子对应得索引
    // { { type: 'mine', x: 0, y: 0 }, { type: 'number', x: 0, y: 0, value: 2 } }
    for (var i = 0; i < this.tr; i++) {
        this.squares[i] = [];
        for (var j = 0; j < this.td; j++) {
            // this.squares[i][j] =;
            // n++;

            // 取一个方块在数组里的数据：行列；找方块周围的方块：坐标。行列与坐标的x,y相反
            if (rn.indexOf(++n) != -1) {
                // 现在的索引在雷的数组，表示这个索引为雷
                this.squares[i][j] = { type: 'mine', x: j, y: i };
            } else {
                this.squares[i][j] = { type: 'number', x: j, y: i, value: 0 };
            }
        }
    }
    // console.log(this.squares);

    // 阻止右键菜单弹出事件
    this.parent.oncontextmenu = function () {
        return false;
    }

    this.updateNum();
    this.createDom();

    // 剩余雷数
    this.mineNumDom = document.querySelector('.mineNum');
    this.mineNumDom.innerHTML = this.surplusMine;
};

// 创建表格
Mine.prototype.createDom = function () {
    var This = this;
    var table = document.createElement('table');
    for (var i = 0; i < this.tr; i++) {
        //行
        var domTr = document.createElement('tr');
        this.tds[i] = [];

        for (var j = 0; j < this.td; j++) {
            //列
            var domTd = document.createElement('td');
            // domTd.innerHTML = 0;

            domTd.pos = [i, j];//把格子对应得行列存到格子身上，为了下面通过这个值去数组里取到对应数据
            domTd.onmousedown = function () {
                This.play(event, this);//This:实例对象；this:点击的那个td
            }

            this.tds[i][j] = domTd; //把所有创建的td添加到数组中

            /*  if (this.squares[i][j].type == 'mine') {
                 domTd.className = 'mine';
             }
             if (this.squares[i][j].type == 'number') {
                 domTd.innerHTML = this.squares[i][j].value;
             } */

            domTr.appendChild(domTd);
        }
        table.appendChild(domTr);
    }
    this.parent.innerHTML = '';//清空上一次创建的,避免多次点击创建多个
    this.parent.appendChild(table);
};

// 找某个格子周围的8格方格
Mine.prototype.getAround = function (square) {
    var x = square.x,
        y = square.y;
    var result = [];//把找到的格子的坐标返回出去，二维数组

    /* 
    x-1,y-1     x,y-1       x+1,y-1
    x-1,y       x,y         x+1,y
    x-1,y+1     x,y+1       x+1,y+1
    */
    // 通过坐标取循环到九宫格  
    for (var i = x - 1; i <= x + 1; i++) {
        for (var j = y - 1; j <= y + 1; j++) {
            if (i < 0 || j < 0 ||                   //超出了左边、上边范围
                i > this.td - 1 || j > this.tr - 1 ||       //右边、下边
                (i == x && j == y) ||               //当前循环到自己
                this.squares[j][i].type == 'mine'   //周围格子为雷
            ) {
                continue;
            }
            result.push([j, i]);//以行列形式返回出去,因为到时候用它取数组里的数据
        }
    }
    return result;
};

// 更新所有的数字 
Mine.prototype.updateNum = function () {
    for (var i = 0; i < this.tr; i++) {
        for (var j = 0; j < this.td; j++) {
            // 只更新的是雷周围的数字
            if (this.squares[i][j].type == 'number') {
                continue;
            }
            var num = this.getAround(this.squares[i][j]);//获取到每个雷周围数字
            // console.log(num);
            for (var k = 0; k < num.length; k++) {
                /* num[i]==[0,1];
                num[i][0]==0;
                num[i][1]==1; */
                this.squares[num[k][0]][num[k][1]].value += 1;
            }
        }
    }
    // console.log(this.squares);
}

// 进行游戏
Mine.prototype.play = function (ev, obj) {
    var This = this;
    if (ev.which == 1 && obj.className != 'flag') {//点击的是左键  /* 后面是限制用户标记完小红旗，就不能左键点击，只能右键取消小红旗 */
        // console.log(obj);
        var curSquare = this.squares[obj.pos[0]][obj.pos[1]];
        var cl = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'];

        if (curSquare.type == 'number') {//用户点击到的是数字
            // console.log('你点到数字了');
            obj.innerHTML = curSquare.value;
            obj.className = cl[curSquare.value];

            // 点到了数字0
            if (curSquare.value == 0) {
                /* 
                1.不显示
                2. 显示自己；找四周（1.显示四周的值不为0，就显示到这里，不需要再找；2.值为0=>显示自己，找四周）
                */
                obj.innerHTML = '';

                function getAllZero(square) {
                    var around = This.getAround(square);//找到了周围n个格子

                    for (var i = 0; i < around.length; i++) {
                        // around[i]=[0,0];
                        var x = around[i][0];//行
                        var y = around[i][1];//列

                        This.tds[x][y].className = cl[This.squares[x][y].value];

                        if (This.squares[x][y].value == 0) {
                            // 如果以某个格子为中心找到格子为0，就接着调用函数(递归)
                            if (!This.tds[x][y].check) {
                                // 给对应td添加一条属性，用于决定这个格子是否有找过.找过：true，下一次就不会在找了
                                This.tds[x][y].check = true;
                                getAllZero(This.squares[x][y]);
                            }
                        } else {
                            This.tds[x][y].innerHTML = This.squares[x][y].value;
                        }
                    }
                }
                getAllZero(curSquare);
            }
        } else {//用户点击到的是雷
            // console.log('你点到雷了');
            this.gameOver(obj);
        }
    }

    if (ev.which == 3) {//点击的是右键
        if (obj.className && obj.className != 'flag') {
            //不能右击数字
            return;
        }
        obj.className = obj.className == 'flag' ? '' : 'flag';//切换class

        if (this.squares[obj.pos[0]][obj.pos[1]].type == 'mine') {
            this.allRight = true;//用户标的小红旗都是雷
        } else {
            this.allRight = false;
        }

        if (obj.className == 'flag') {
            this.mineNumDom.innerHTML = --this.surplusMine;
        } else {
            this.mineNumDom.innerHTML = ++this.surplusMine;
        }

        if (this.surplusMine == 0) {
            // 剩余雷的数量为0，用户标完小红旗,判断游戏成功或失败
            if (this.allRight) {
                // 用户全部标对，游戏成功
                alert('恭喜你，游戏通过');
            } else {
                this.gameOver();
                alert('游戏失败');
            }
        }
    }
}

// 游戏失败
Mine.prototype.gameOver = function (clickTd) {
    /* 
    1.显示所有的雷
    2.取消所有格子点击事件
    3.给点中的格子的雷标记一个红
    */
    for (var i = 0; i < this.tr; i++) {
        for (var j = 0; j < this.td; j++) {
            if (this.squares[i][j].type == 'mine') {
                this.tds[i][j].className = 'mine';
            }
            this.tds[i][j].onmousedown = null;
        }
    }

    if (clickTd) {
        clickTd.style.backgroundColor = '#f00';
    }
}

/* var mine = new Mine(28, 28, 99);
mine.init(); */
// console.log(mine.getAround(mine.squares[0][0]));

// 上边button功能
var btns = document.querySelectorAll('.level button');
var mine = null;//存储生成对的实例
var ln = 0;//处理当前选中的状态
var arr = [[9, 9, 10], [16, 16, 40], [28, 28, 99]];//不同级别的行列数，雷数

for (let i = 0; i < btns.length - 1; i++) {
    btns[i].onclick = function () {
        btns[ln].className = '';
        this.className = 'active';

        mine = new Mine(...arr[i]);
        mine.init();

        ln = i;

        /* btns[3].onclick = function () {//重新开始(自己写的)
            mine = new Mine(...arr[i]);
            mine.init();
        } */
    }
}
btns[0].onclick();//默认生成初级,初始化
btns[3].onclick = function () {//重新开始
    mine.init();
}
